import {PageFileType, PagesOptionsPage} from "../types";
import {ConfigLoader} from "./config";
import fg from "fast-glob";
import {PageParser} from "../utils/PageParser";
import {mergeObjects} from "../utils/merge";
import {arrayToMap} from "../utils/array";
import path from "path";
import {PathUtil} from "../utils/PathUtil";

/**
 * 扫描类型
 */
export type pagesType = 'main' | 'sub';

export class PagesLoader {

    /**
     * 配置加载器
     */
    private readonly configLoader: ConfigLoader;

    /**
     * 页面配置
     */
    private pages: Map<string, PagesOptionsPage> = new Map<string, PagesOptionsPage>();
    /**
     * 分包页面配置
     */
    private subPages: Map<string, PagesOptionsPage> = new Map<string, PagesOptionsPage>();

    /**
     * 页面解析器
     */
    private pageParser: PageParser;

    constructor(configLoader: ConfigLoader) {
        this.configLoader = configLoader;
        this.pageParser = new PageParser();
    }

    /**
     * 扫描指定目录下的所有页面文件路径
     * @param entryDir 入口目录，相对于项目根目录
     * @param fileTypes 页面文件类型
     * @returns 页面文件路径列表，相对于项目根目录
     */
    private scanPagePaths(entryDir: string, fileTypes: PageFileType[]): string[] {
        // 构建文件类型匹配模式
        const fileExtensions = fileTypes.map(type => `*.${type}`);
        const globPattern = fileExtensions.length === 1
            ? `${entryDir}/**/${fileExtensions[0]}`
            : `${entryDir}/**/*.{${fileTypes.join(',')}}`;

        // 使用fast-glob扫描文件
        return fg.sync(globPattern, {
            cwd: this.configLoader.plugin.root,
            ignore: this.configLoader.plugin.ignore,
            onlyFiles: true,
            absolute: false
        });
    }

    /**
     * 统一的页面扫描方法
     * @param type 扫描类型：'main' 扫描主包页面，'sub' 扫描分包页面
     * @param paths 页面路径，为空时扫描所有页面，否则按需扫描
     */
    public scanPages(type: pagesType, paths?: string[]) {
        const isSubPages = type === 'sub';
        const targetMap = isSubPages ? this.subPages : this.pages;

        // 如果没有传入paths参数，清空缓存并扫描全部
        if (paths === undefined) {
            targetMap.clear();
        }

        // 分包扫描：如果没有分包配置，直接返回
        if (isSubPages && (!this.configLoader.pages.subPackages || this.configLoader.pages.subPackages.length === 0)) {
            return;
        }

        // 主包扫描：获取分包根目录列表，用于排除分包页面
        const subPackageRoots = !isSubPages && this.configLoader.pages.subPackages
            ? this.configLoader.pages.subPackages.map(pkg => pkg.root)
            : [];

        // 确定要扫描的包列表
        const packagesToScan = isSubPages
            ? this.configLoader.pages.subPackages!
            : [{root: this.configLoader.plugin.mainDir, pages: this.configLoader.pages.pages}];

        for (let packageInfo of packagesToScan) {
            // 确定页面文件列表
            const pageFiles = paths !== undefined && paths.length > 0
                ? (isSubPages ? paths.filter(p => p.startsWith(PathUtil.join(this.configLoader.plugin.entryDir!, packageInfo.root))) : paths)
                : this.scanPagePaths(PathUtil.join(this.configLoader.plugin.entryDir, packageInfo.root), this.configLoader.plugin.fileTypes);

            // 获取已知的页面配置
            const knownPages = packageInfo.pages || [];
            const pagesMap = arrayToMap(knownPages, item => item.path, item => item);

            for (let filePath of pageFiles) {
                const pagePath = PageParser.convertToPagePath(filePath);

                // 主包扫描：检查是否在分包目录下，如果是则跳过
                if (!isSubPages) {
                    const isInSubPackage = subPackageRoots.some(root => pagePath.startsWith(root + '/'));
                    if (isInSubPackage) {
                        continue;
                    }
                }

                // 计算相对路径和存储key
                const relativePagePath = isSubPages && pagePath.startsWith(packageInfo.root + '/')
                    ? pagePath.substring(packageInfo.root.length + 1)
                    : pagePath;

                const storageKey = isSubPages
                    ? `${packageInfo.root}/${relativePagePath}`
                    : pagePath;

                const absoluteFilePath = path.join(this.configLoader.plugin.root!, filePath);
                // 解析页面配置
                const pageConfig = this.pageParser.parsePageOptions(absoluteFilePath);
                // 获取已配置的配置
                const pagesConfig = pagesMap.has(relativePagePath) ? pagesMap.get(relativePagePath) : undefined;
                const {
                    path: mergePagePath,
                    ...mergedConfig
                } = mergeObjects(this.configLoader.plugin.defaultPageConfig as PagesOptionsPage || {}, pagesConfig, pageConfig);

                // 生成最终页面配置
                const finalPageConfig: PagesOptionsPage = {
                    // 空路径默认为index
                    path: relativePagePath || 'index',
                    ...mergedConfig
                };

                targetMap.set(storageKey, finalPageConfig);
            }
        }
    }

    get main() {
        return this.pages;
    }

    get sub() {
        return this.subPages;
    }
}